#include <mips/regdef.h>
#include <sys/syscall.h>

#define RES_OK 0
#define ERROR_LECTURA -2
#define ERROR_ESCRITURA -1

	.text
	.align 2	
	.global base64_encode
	.ent	base64_encode
base64_encode:
	.frame	 $fp, 48,  ra
	.set	noreorder
	.cpload	t9
	.set	reorder
	subu	sp, sp, 48
	.cprestore 44
	sw		 $fp, 40(sp)		#Guardo el $fp en el frame
	sw		 ra, 36(sp)			#Guardo el ra en el frame
	move	 $fp,  sp			#Seteo el $fp

	sw		a0, 48($fp)			#a0: fdin
	sw		a1, 52($fp)			#a1: fdout

	sw		s0, 28($fp)			#s0: count
	sw		s1, 24($fp)			#s1: block_count

	move	s0, zero
	move	s1, zero
	sw	 	zero, 20($fp)		#Inicializo el encode_block
	sw	 	zero, 16($fp)		#Inicializo el buffer


COND_while_encode:
	la		a0, 20($fp)		#a0: puntero al encode_block
	lw		a1, 48($fp)		#a1: fdin

	jal		read_from_input

	move	s0, v0
	li		t0, 3
	bne		s0, t0, END_while_encode

BODY_while_encode:
	sw		zero, 16($fp)	#Inicializo el buffer

	la		a0, 16($fp)		#a0: puntero al buffer
	or		t0, zero, zero
	or		t1, zero, zero
	or		t2, zero, zero
	or		a1, zero, zero

	lbu		t0, 20($fp)
	sll		t0, t0, 24
	lbu		t1, 21($fp)
	sll		t1, t1, 16
	lbu		t2, 22($fp)
	sll		t2, t2, 8
	or		a1, t0, t1
	or		a1, a1, t2		#a2: bloque ya leido
	li		a2, 24			#a2: bits a escribir
	lw		a3, 52($fp)		#a3: fdout

	jal		write_buffer

	bnez	v0, error_escritura	#Si hubo un error retorno, devolviendo el valor de error

	addiu	s1, s1, 1

if_1:
	li		t0, 19
	move	t2, s1
	divu	t2, t0			#block_count div 19
	mfhi 	t1				#t1 = s1 % t0

	bnez	t1, end_if1		#if(blocks_count % 19 != 0) salto

	li		v0, SYS_write	# ver dentro de <sys/syscall.h>.
	lw		a0, 52($fp)		# a0: fdout
	la		a1, CRLF       	# a1: Almaceno en a1 el caracter CRLF.
	li		a2, 1	      	# a2: bytes a escribir: 1b.

	syscall

	bne 	 zero, a3, error_escritura	#Si a3 != 0, error de escritura
	li		 t0, 1
	bne 	 v0, t0, error_escritura	#Si v0 != 1, error de escritura

end_if1:
	b		COND_while_encode

END_while_encode:
	li		t0, ERROR_LECTURA
	beq		t0, s0, error_lectura

if_2:
	li		t0, 2
	bne		s0, t0, else_if2

	sw		zero, 16($fp)	#Inicializo el buffer

	la		a0, 16($fp)		#a0: puntero al buffer
	or		t0, zero, zero
	or		t1, zero, zero
	or		a1, zero, zero

	lbu		t0, 20($fp)
	sll		t0, t0, 24
	lbu		t1, 21($fp)
	sll		t1, t1, 16
	or		a1, t0, t1		#a1: bloque ya leido
	li		a2, 18			#a2: bits a escribir
	lw		a3, 52($fp)		#a3: fdout

	jal		write_buffer

	bnez	v0, error_escritura	#Si hubo un error retorno, devolviendo el valor de error

	lw		a0, 52($fp)

	jal		push_padding

	bnez	v0, error_escritura	#Si hubo un error retorno, devolviendo el valor de error


end_if2:
	b	end_ifs

else_if2:

	li		t0, 1
	bne		s0, t0, end_ifs

	sw		zero, 16($fp)	#Inicializo el buffer

	la		a0, 16($fp)		#a0: puntero al buffer

	or		t0, zero, zero
	or		a1, zero, zero

	lbu		t0, 20($fp)
	sll		t0, t0, 24
	move 	a1, t0			#a1: bloque ya leido
	li		a2, 12			#a2: bits a escribir
	lw		a3, 52($fp)		#a3: fdout

	jal		write_buffer

	bnez	v0, error_escritura	#Si hubo un error retorno, devolviendo el valor de error

	lw		a0, 52($fp)

	jal		push_padding

	bnez	v0, error_escritura	#Si hubo un error retorno, devolviendo el valor de error

	jal		push_padding

	bnez	v0, error_escritura	#Si hubo un error retorno, devolviendo el valor de error

end_ifs:

if_3:

	li		t0, 19
	div		s1, t0			#block_count div 19
	mfhi 	t1				#t1 = s1 % t0

	bnez	t1, end_if3		#if(blocks_count % 19 != 0) salto

	li		t0, 3
	move	t2, s0
	divu	t2, t0			#count div 3
	mfhi 	t1				#t1 = s1 % t0

	beq		zero,t1, end_if3		#if(count % 3 == 0) salto

	li		v0, SYS_write	# ver dentro de <sys/syscall.h>.
	lw		a0, 52($fp)		# a0: fdout
	la		a1, CRLF       	# a1: Almaceno en a1 el caracter CRLF.
	li		a2, 1	      	# a2: bytes a escribir: 1b.

	syscall

	bne 	 zero, a3, error_escritura	#Si a3 != 0, error de escritura
	li		 t0, 1
	bne 	 v0, t0, error_escritura	#Si v0 != 1, error de escritura

end_if3:
	li		v0, RES_OK
	b		return_encode_file

error_lectura:
	li		v0, 2				#Seteo el valor de retorno
	b		return_encode_file

error_escritura:
	li		v0, ERROR_ESCRITURA	#Seteo el valor de retorno
	b		return_encode_file

return_encode_file:
	lw		s0, 28($fp)		#Restauro s0
	lw		s1, 24($fp)		#Restauro s1

	lw		$fp, 40(sp)		#Recupero $fp
	lw		ra, 36(sp)		#Recupero ra

	addiu	sp, sp, 48 		#Restauro el stack
	j	ra
	.end	base64_encode

	.data
	.rdata
	.align 2
PADDING:
	.asciiz "="
CRLF:
	.asciiz "\n"

	.global errmsg
errmsg:
	.word errmsg_0, errmsg_1, errmsg_2, errmsg_3, errmsg_4, errmsg_5
	.size errmsg, 24
	.align 0
errmsg_0:
	.asciiz "No se pudo escribir en el archivo"
errmsg_1:
	.asciiz "No se pudo leer del archivo"
errmsg_2:
	.asciiz "Caracter invalido"
errmsg_3:
	.asciiz "Padding invalido"
errmsg_4:
	.asciiz "Padding antes de fin de archivo"
errmsg_5:
	.asciiz "Fin de archivo inesperado"
